/**
 * 
 */
package com.talos.framework.common.util.string;

import cn.hutool.core.text.StrFormatter;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 〈功能详细描述〉
 * 
 * @author Nail.zhang
 * @version [V0.1, Jan 10, 2012]
 */
public class StringUtils extends org.apache.commons.lang3.StringUtils {


	private static Pattern linePattern = Pattern.compile("_(\\w)");
	private static Pattern humpPattern = Pattern.compile("[A-Z]");

	/** 空字符串 */
	private static final String NULLSTR = "";

	/** 下划线 */
	private static final char SEPARATOR = '_';

	/**
	 * 下划线转驼峰
	 */
	public static String lineToHump(String str) {
		str = str.toLowerCase();
		Matcher matcher = linePattern.matcher(str);
		StringBuffer sb = new StringBuffer();
		while (matcher.find()) {
			matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
		}
		matcher.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 驼峰转下划线
	 */
	public static String humpToLine2(String str) {
		Matcher matcher = humpPattern.matcher(str);
		StringBuffer sb = new StringBuffer();
		while (matcher.find()) {
			matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
		}
		matcher.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 第一个字母小写
	 * 
	 * @param str
	 * @return
	 */
	public static String firstWordToLowerCase(String str) {
		return str.substring(0, 1).toLowerCase() + str.substring(1, str.length());
	}

	public static String firstTwoWordToLowerCase(String str) {
		return str.substring(0, 2).toLowerCase() + str.substring(2, str.length());
	}

	public static String firstWordToUpperCase(String str) {
		return str.substring(0, 1).toUpperCase() + str.substring(1, str.length());
	}

	/**
	 * 
	 * @param str
	 * @param digit
	 * @param seperator
	 * @return
	 */
	public static String format(String str, int digit, String seperator) {
		int len = str.length();
		int count = len / digit;
		int remainder = len % digit;
		String returnStr = "";
		for (int i = 1; i <= count; i++) {
			if (i == count && remainder == 0)
				returnStr += str.substring((i - 1) * digit, i * digit);
			else
				returnStr += str.substring((i - 1) * digit, i * digit) + seperator;
		}
		returnStr += str.substring(len - remainder);
		return returnStr;
	}

	/**
	 * 格式化字符串
	 * 
	 * @param srcStr
	 *            {0}{1}{2}
	 * @param obj
	 * @return
	 */
	public static String format(String srcStr, String... obj) {

		String[] searchList = new String[obj.length];
		for (int i = 0; i < searchList.length; i++) {
			searchList[i] = "{" + i + "}";

		}
		srcStr = StringUtils.replaceEach(srcStr, searchList, obj);
		return srcStr;

	}

	public static int length(String value) {
		int valueLength = 0;
		String chinese = "[\u0391-\uFFE5]";
		/* 获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1 */
		for (int i = 0; i < value.length(); i++) {
			/* 获取一个字符 */
			String temp = value.substring(i, i + 1);
			/* 判断是否为中文字符 */
			if (temp.matches(chinese)) {
				/* 中文字符长度为2 */
				valueLength += 2;
			} else {
				/* 其他字符长度为1 */
				valueLength += 1;
			}
		}
		return valueLength;
	}


	 public static boolean containsEmoji(String source) {
	        int len = source.length();
	        boolean isEmoji = false;
	        for (int i = 0; i < len; i++) {
	            char hs = source.charAt(i);
	            if (0xd800 <= hs && hs <= 0xdbff) {
	                if (source.length() > 1) {
	                    char ls = source.charAt(i + 1);
	                    int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
	                    if (0x1d000 <= uc && uc <= 0x1f77f) {
	                        return true;
	                    }
	                }
	            } else {
	                // non surrogate
	                if (0x2100 <= hs && hs <= 0x27ff && hs != 0x263b) {
	                    return true;
	                } else if (0x2B05 <= hs && hs <= 0x2b07) {
	                    return true;
	                } else if (0x2934 <= hs && hs <= 0x2935) {
	                    return true;
	                } else if (0x3297 <= hs && hs <= 0x3299) {
	                    return true;
	                } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d
	                        || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c
	                        || hs == 0x2b1b || hs == 0x2b50 || hs == 0x231a) {
	                    return true;
	                }
	                if (!isEmoji && source.length() > 1 && i < source.length() - 1) {
	                    char ls = source.charAt(i + 1);
	                    if (ls == 0x20e3) {
	                        return true;
	                    }
	                }
	            }
	        }
	        return isEmoji;
	    }

	    private static boolean isEmojiCharacter(char codePoint) {
	        return (codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA)
	                || (codePoint == 0xD)
	                || ((codePoint >= 0x20) && (codePoint <= 0xD7FF))
	                || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))
	                || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
	    }

	    /**
	     * 过滤emoji 或者 其他非文字类型的字符
	     * 
	     * @param source
	     * @return
	     */
	    public static String filterEmoji(String source) {
	        if (StringUtils.isBlank(source)) {
	            return source;
	        }
	        StringBuilder buf = null;
	        int len = source.length();
	        for (int i = 0; i < len; i++) {
	            char codePoint = source.charAt(i);
	            if (isEmojiCharacter(codePoint)) {
	                if (buf == null) {
	                    buf = new StringBuilder(source.length());
	                }
	                buf.append(codePoint);
	            }
	        }
	        if (buf == null) {
	            return source;
	        } else {
	            if (buf.length() == len) {
	                buf = null;
	                return source;
	            } else {
	                return buf.toString();
	            }
	        }
	    }
	    
	    public static String filterOffUtf8Mb4(String text) throws UnsupportedEncodingException {
	        byte[] bytes = text.getBytes("utf-8");
	        ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
	        int i = 0;
	        while (i < bytes.length) {
	            short b = bytes[i];
	            if (b > 0) {
	                buffer.put(bytes[i++]);
	                continue;
	            }

	            b += 256; // 去掉符号位

	            if (((b >> 5) ^ 0x6) == 0) {
	                buffer.put(bytes, i, 2);
	                i += 2;
	            } else if (((b >> 4) ^ 0xE) == 0) {
	                buffer.put(bytes, i, 3);
	                i += 3;
	            } else if (((b >> 3) ^ 0x1E) == 0) {
	                i += 4;
	            } else if (((b >> 2) ^ 0x3E) == 0) {
	                i += 5;
	            } else if (((b >> 1) ^ 0x7E) == 0) {
	                i += 6;
	            } else {
	                buffer.put(bytes[i++]);
	            }
	        }
	        buffer.flip();
	        return new String(buffer.array(), "utf-8");
	    }


	/**
	 * 截取字符串
	 *
	 * @param str 字符串
	 * @param start 开始
	 * @return 结果
	 */
	public static String substring(final String str, int start)
	{
		if (str == null)
		{
			return NULLSTR;
		}

		if (start < 0)
		{
			start = str.length() + start;
		}

		if (start < 0)
		{
			start = 0;
		}
		if (start > str.length())
		{
			return NULLSTR;
		}

		return str.substring(start);
	}

	/**
	 * 截取字符串
	 *
	 * @param str 字符串
	 * @param start 开始
	 * @param end 结束
	 * @return 结果
	 */
	public static String substring(final String str, int start, int end)
	{
		if (str == null)
		{
			return NULLSTR;
		}

		if (end < 0)
		{
			end = str.length() + end;
		}
		if (start < 0)
		{
			start = str.length() + start;
		}

		if (end > str.length())
		{
			end = str.length();
		}

		if (start > end)
		{
			return NULLSTR;
		}

		if (start < 0)
		{
			start = 0;
		}
		if (end < 0)
		{
			end = 0;
		}

		return str.substring(start, end);
	}

	/**
	 * 格式化文本, {} 表示占位符<br>
	 * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
	 * 如果想输出 {} 使用 \\转义 { 即可，如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
	 * 例：<br>
	 * 通常使用：format("this is {} for {}", "a", "b") -> this is a for b<br>
	 * 转义{}： format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
	 * 转义\： format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
	 *
	 * @param template 文本模板，被替换的部分用 {} 表示
	 * @param params 参数值
	 * @return 格式化后的文本
	 */
	public static String format(String template, Object... params)
	{
		if (params==null || params.length<=0)
		{
			return template;
		}
		return StrFormatter.format(template, params);
	}

	/**
	 * 字符串转set
	 *
	 * @param str 字符串
	 * @param sep 分隔符
	 * @return set集合
	 */
	public static final Set<String> str2Set(String str, String sep)
	{
		return new HashSet<String>(str2List(str, sep, true, false));
	}

	/**
	 * 字符串转list
	 *
	 * @param str 字符串
	 * @param sep 分隔符
	 * @param filterBlank 过滤纯空白
	 * @param trim 去掉首尾空白
	 * @return list集合
	 */
	public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
	{
		List<String> list = new ArrayList<String>();
		if (StringUtils.isEmpty(str))
		{
			return list;
		}

		// 过滤空白字符串
		if (filterBlank && StringUtils.isBlank(str))
		{
			return list;
		}
		String[] split = str.split(sep);
		for (String string : split)
		{
			if (filterBlank && StringUtils.isBlank(string))
			{
				continue;
			}
			if (trim)
			{
				string = string.trim();
			}
			list.add(string);
		}

		return list;
	}

	/**
	 * 下划线转驼峰命名
	 */
	public static String toUnderScoreCase(String str)
	{
		if (str == null)
		{
			return null;
		}
		StringBuilder sb = new StringBuilder();
		// 前置字符是否大写
		boolean preCharIsUpperCase = true;
		// 当前字符是否大写
		boolean curreCharIsUpperCase = true;
		// 下一字符是否大写
		boolean nexteCharIsUpperCase = true;
		for (int i = 0; i < str.length(); i++)
		{
			char c = str.charAt(i);
			if (i > 0)
			{
				preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
			}
			else
			{
				preCharIsUpperCase = false;
			}

			curreCharIsUpperCase = Character.isUpperCase(c);

			if (i < (str.length() - 1))
			{
				nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
			}

			if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
			{
				sb.append(SEPARATOR);
			}
			else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
			{
				sb.append(SEPARATOR);
			}
			sb.append(Character.toLowerCase(c));
		}

		return sb.toString();
	}

	/**
	 * 是否包含字符串
	 *
	 * @param str 验证字符串
	 * @param strs 字符串组
	 * @return 包含返回true
	 */
	public static boolean inStringIgnoreCase(String str, String... strs)
	{
		if (str != null && strs != null)
		{
			for (String s : strs)
			{
				if (str.equalsIgnoreCase(trim(s)))
				{
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。 例如：HELLO_WORLD->HelloWorld
	 *
	 * @param name 转换前的下划线大写方式命名的字符串
	 * @return 转换后的驼峰式命名的字符串
	 */
	public static String convertToCamelCase(String name)
	{
		StringBuilder result = new StringBuilder();
		// 快速检查
		if (name == null || name.isEmpty())
		{
			// 没必要转换
			return "";
		}
		else if (!name.contains("_"))
		{
			// 不含下划线，仅将首字母大写
			return name.substring(0, 1).toUpperCase() + name.substring(1);
		}
		// 用下划线将原始字符串分割
		String[] camels = name.split("_");
		for (String camel : camels)
		{
			// 跳过原始字符串中开头、结尾的下换线或双重下划线
			if (camel.isEmpty())
			{
				continue;
			}
			// 首字母大写
			result.append(camel.substring(0, 1).toUpperCase());
			result.append(camel.substring(1).toLowerCase());
		}
		return result.toString();
	}

	/**
	 * 驼峰式命名法 例如：user_name->userName
	 */
	public static String toCamelCase(String s)
	{
		if (s == null)
		{
			return null;
		}
		s = s.toLowerCase();
		StringBuilder sb = new StringBuilder(s.length());
		boolean upperCase = false;
		for (int i = 0; i < s.length(); i++)
		{
			char c = s.charAt(i);

			if (c == SEPARATOR)
			{
				upperCase = true;
			}
			else if (upperCase)
			{
				sb.append(Character.toUpperCase(c));
				upperCase = false;
			}
			else
			{
				sb.append(c);
			}
		}
		return sb.toString();
	}

	@SuppressWarnings("unchecked")
	public static <T> T cast(Object obj)
	{
		return (T) obj;
	}


	/**
	 * * 判断一个对象是否为空
	 *
	 * @param object Object
	 * @return true：为空 false：非空
	 */
	public static boolean isNull(Object object)
	{
		return object == null;
	}

	/**
	 * * 判断一个对象是否非空
	 *
	 * @param object Object
	 * @return true：非空 false：空
	 */
	public static boolean isNotNull(Object object)
	{
		return !isNull(object);
	}

}
